package http

import (
	"fmt"
	"net/http"
	"net/url"
	"regexp"
	"strings"

	library ".."
	dispatcher "../dispatcher"
	httpdata "../httpdata"
	"../log"
)

// Log 全局日志
var Log = log.GetLog("library")

// LogTimeout 超时
var LogTimeout *log.Timeout

// HTTP http库
type HTTP struct {
	Buffer   library.Buffer      // 链接缓冲
	Dispatch dispatcher.Dispatch // 链接调度
	Handle   map[*Routing]Handle // 路由接口
}

// ServeHTTP 默认接口
func (H *HTTP) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// 0. 得到调度
	// 1. 得到对象缓冲
	// 2. 发送对象到调度
	// 3. 调度器调度缓冲对象到目标路由,约束IP等信息,接口执行超时等
	// 4. 得到结果解锁调度,完成通信周期
	// 得到调度
	dispatch := H.Dispatch.Get() // 先得到调度不然会引起缓冲溢出
	// 得到缓冲
	buffer, link := H.getBuffer()
	if !buffer.Employ {
		return
	}
	// 设置数据
	link.w = w
	link.r = r
	// 发送到调度
	dispatch.Set(buffer.Value)
	// 等待调度结束
	<-dispatch.Lock
	buffer.Employ = false
}

// Init 初始化
func (H *HTTP) Init(min int, max int) {
	// 初始化
	H.Buffer.Init(max) // 缓存
	H.Handle = make(map[*Routing]Handle)
	// 初始化超时
	LogTimeout = Log.GetTimeout()
	// 调度
	H.Dispatch.Init(min, max, true, true, func(value interface{}) int {
		// 转换类型
		link := value.(*LinkHTTP)
		defer link.r.Body.Close()
		// 获得 url 路径
		strURL, _ := url.PathUnescape(link.r.URL.String())
		N := strings.Index(strURL, "?")
		if N != -1 {
			strURL = (strURL)[:N]
		}
		// 处理
		dispose := func(R *Routing, H Handle) {
			// 是否启用限制
			if R.UsingVisitLimit {
				addr := strings.Split(link.r.RemoteAddr, ":")
				if ok, fun := R.VisitLimit.LimitCondition(addr[0], addr[1]); !ok {
					// 关闭还原
					defer fun()
				} else {
					Log.WarnS(fmt.Sprintf("用户限制访问: %v\n", *link.r))
					// 设置状态
					link.w.WriteHeader(http.StatusUnauthorized)
					link.w.Write(httpdata.GetFound(http.StatusUnauthorized))
					return
				}
			}
			// 超时判断
			if R.TimeoutDetection {
				defer LogTimeout.Detection(R.TimeoutMin, R.TimeoutMax, fmt.Sprintf("请求执行超时: %v\n", *link.r))()
			}
			// 设置跨域
			if R.CrossDomain {
				link.w.Header().Set("Access-Control-Allow-Origin", "*")
			}
			// 调用处理
			H.ServeHTTP(link.w, link.r)
		}
		// 优先判断绝对访问
		for R, H := range H.Handle {
			// 判断路径
			if !R.RegExp {
				//绝对路径访问
				if R.Path == strURL {
					dispose(R, H)
					return 0
				}
			}
		}
		// 判断正则访问
		for R, H := range H.Handle {
			// 判断路径
			if R.RegExp {
				// 使用正则匹配
				if ok, _ := regexp.MatchString(R.Path, strURL); ok {
					dispose(R, H)
					return 0
				}
			}
		}
		// 日志记录
		Log.WarnS(fmt.Sprintf("路由异常访问: %v\n", *link.r))
		// 返回错误
		link.w.WriteHeader(http.StatusNotFound)
		link.w.Write(httpdata.GetFound(http.StatusNotFound))
		return 0
	})
}

// Listen 初始化
func (H *HTTP) Listen(addr string) {
	// 创建路由
	mux := http.NewServeMux()
	mux.Handle("/", H)
	// 注册
	err := http.ListenAndServe(addr, mux)
	if err != nil {
		Log.ErrorS(fmt.Sprintf("链接失败: %v", err))
	}
}

// getBuffer 得到缓冲
func (H *HTTP) getBuffer() (Buffer *library.BufferByte, link *LinkHTTP) {
	// 获得缓冲
	Buffer = H.Buffer.Get()
	if Buffer.Value == nil {
		link = &LinkHTTP{}
		Buffer.Value = link
	} else {
		if add, ok := Buffer.Value.(*LinkHTTP); ok {
			link = add
		} else {
			Buffer.Employ = false
			Log.ErrorS("获取缓存失败,断言无效")
		}
	}
	return
}
